import { parse } from "@babel/parser";
import traverse, { type NodePath, type Node } from "@babel/traverse";
import generator from "@babel/generator";
import { globSync } from "glob";
import { readFileSync, writeFileSync, existsSync } from "node:fs";
import { parse as vueParser } from "@vue/compiler-sfc";
import { createHash } from "crypto";
import gogocode from "gogocode";

interface IGoGoNodeAttr {
  type: string;
  content: string;
  startPosition: number;
  endPosition: number;
}

// 配置参数集中管理
const CONFIG = {
  SRC_DIR: "test",
  FILE_TYPES: ["js", "vue"],
  LANG_FILE: "locales/zh-CN.json",
  I18N_FUNC: "$t",
  CHINESE_REGEX: /[\u4E00-\u9FA5\u3000-\u303F\uFF00-\uFFEF]+/
};

// 日志输出
function logInfo(msg: string) {
  console.log("[INFO]", msg);
}
function logError(msg: string) {
  console.error("[ERROR]", msg);
}

// 读取语言包
function readLangObj() {
  try {
    if (!existsSync(CONFIG.LANG_FILE)) {
      writeFileSync(CONFIG.LANG_FILE, "{}", { flag: "w" });
    }
    const langContent = readFileSync(CONFIG.LANG_FILE, "utf-8");
    return JSON.parse(langContent);
  } catch (e) {
    logError("读取语言包失败: " + e);
    return {};
  }
}
// 写入语言包
function writeLangObj(langObj: Record<string, string>) {
  try {
    writeFileSync(CONFIG.LANG_FILE, JSON.stringify(langObj, null, 2));
  } catch (e) {
    logError("写入语言包失败: " + e);
  }
}
// 生成唯一key
function genKey(str: string) {
  return createHash("md5").update(str).digest("hex").substring(0, 8);
}
// 属性处理
function handleAttrs(attrs: any[], langObj: Record<string, string>, updateLang: () => void) {
  attrs.forEach((item) => {
    const attr = item as unknown as {
      key: IGoGoNodeAttr;
      value: IGoGoNodeAttr;
      startWrapper: IGoGoNodeAttr;
      endWrapper: IGoGoNodeAttr;
    };
    const { key, value } = attr;
    const keyContent = key.content || "";
    if (value && value.content) {
      if (["v-", ":", "@"].some((p) => keyContent.startsWith(p))) {
        if (value.content.search(CONFIG.CHINESE_REGEX) > -1) {
          try {
            const inlineAst = parse(value.content, { sourceType: "module" });
            traverse(inlineAst, {
              StringLiteral(path) {
                if (CONFIG.CHINESE_REGEX.test(path.node.value)) {
                  const k = genKey(path.node.value);
                  if (!langObj[k]) {
                    langObj[k] = path.node.value;
                    updateLang();
                  }
                  path.replaceWithSourceString(`${CONFIG.I18N_FUNC}('${k}')`);
                }
              },
            });
            const code = generator(inlineAst).code;
            attr.value.content = code.endsWith(";") ? code.slice(0, -1) : code;
          } catch (e) {
            logError("属性表达式解析失败: " + e);
          }
        }
      } else {
        if (CONFIG.CHINESE_REGEX.test(value.content)) {
          const k = genKey(value.content);
          if (!langObj[k]) {
            langObj[k] = value.content;
            updateLang();
          }
          attr.value.content = `${CONFIG.I18N_FUNC}('${k}')`;
          attr.key.content = `:${keyContent}`;
        }
      }
    }
  });
}
// 文本节点处理
function handleTextNode(item: any, langObj: Record<string, string>, updateLang: () => void) {
  // @ts-ignore
  if (item.nodeType === "text") {
    // @ts-ignore
    const value = item.content.value as unknown as IGoGoNodeAttr;
    if (value.content.trim().startsWith("{{") && value.content.trim().endsWith("}}")) {
      try {
        const inlineAst = parse(value.content.trim().replace(/^{{/, "").replace(/}}$/, ""), { sourceType: "module" });
        traverse(inlineAst, {
          StringLiteral(path) {
            if (CONFIG.CHINESE_REGEX.test(path.node.value)) {
              const k = genKey(path.node.value);
              if (!langObj[k]) {
                langObj[k] = path.node.value;
                updateLang();
              }
              path.replaceWithSourceString(`${CONFIG.I18N_FUNC}('${k}')`);
            }
          },
        });
        const code = generator(inlineAst).code;
        value.content = "{{" + (code.endsWith(";") ? code.slice(0, -1) : code) + "}}";
      } catch (e) {
        logError("插值表达式解析失败: " + e);
      }
    } else {
      if (CONFIG.CHINESE_REGEX.test(value.content)) {
        const k = genKey(value.content);
        if (!langObj[k]) {
          langObj[k] = value.content;
          updateLang();
        }
        value.content = `{{${CONFIG.I18N_FUNC}('${k}')}}`;
      }
    }
  }
}
// JS/TS字符串处理
function handleStringLiteral(path: any, langObj: Record<string, string>, updateLang: () => void) {
  if (CONFIG.CHINESE_REGEX.test(path.node.value)) {
    const k = genKey(path.node.value);
    if (!langObj[k]) {
      langObj[k] = path.node.value;
      updateLang();
    }
    path.replaceWithSourceString(`${CONFIG.I18N_FUNC}('${k}')`);
  }
}

function processVueFile(file: string, content: string, langObj: Record<string, string>, updateLang: () => void) {
  const { descriptor } = vueParser(content);
  let isModified = false;
  const { template, script } = descriptor;
  if (template && template.ast) {
    const templateAst = gogocode(template.content, { parseOptions: { html: true, attachComment: true } });
    templateAst.find(["<$_$></$_$>", "<$_$ />"]).each((node: any) => {
      const attrs = node.attr("content.attributes");
      if (Array.isArray(attrs) && attrs.length) {
        handleAttrs(attrs, langObj, updateLang);
        isModified = true;
      }
      const children = node.attr("content.children");
      if (Array.isArray(children) && children.length) {
        children.forEach((item: any) => {
          handleTextNode(item, langObj, updateLang);
          isModified = true;
        });
      }
    });
    const code = templateAst.generate();
    descriptor.template!.content = code;
    isModified = true;
  }
  if (script) {
    try {
      const scriptAst = parse(script.content, { sourceType: "module", plugins: ["jsx", "typescript"] });
      traverse(scriptAst, {
        StringLiteral(path) {
          handleStringLiteral(path, langObj, updateLang);
          isModified = true;
        },
      });
      descriptor.script!.content = generator(scriptAst).code;
    } catch (e) {
      logError("脚本解析失败: " + e);
    }
  }
  if (isModified) {
    const styles = descriptor.styles.map(({ content, lang, scoped, src }) => {
      const langProp = lang ? `lang=\"${lang}\"` : "";
      const scopedProp = scoped ? `lang=\"${scoped}\"` : "";
      return `\n<style ${langProp} ${scopedProp}>\n${content}\n</style>`;
    }).join("\n");
    const newContent = [
      descriptor.template ? `<template>${descriptor.template.content}</template>` : "",
      descriptor.script ? `<script>${descriptor.script.content}</script>` : "",
      styles,
    ].join("\n");
    writeFileSync(file, newContent);
    logInfo(`已处理并写入: ${file}`);
  }
}

function processJsFile(file: string, content: string, langObj: Record<string, string>, updateLang: () => void) {
  try {
    const ast = parse(content, { sourceType: "module", plugins: ["jsx", "typescript"] });
    traverse(ast, {
      StringLiteral(path) {
        console.log(path.parentKey);
        
        handleStringLiteral(path, langObj, updateLang);
      },
    });
    writeFileSync(file, generator(ast).code);
    logInfo(`已处理并写入: ${file}`);
  } catch (e) {
    logError("JS/TS文件解析失败: " + e);
  }
}

function start() {
  const fileList = globSync(`${CONFIG.SRC_DIR}/**/*.{${CONFIG.FILE_TYPES.join(",")}}`);
  let langObj = readLangObj();
  const updateLang = () => writeLangObj(langObj);
  fileList.forEach((file) => {
    try {
      const ext = file.split(".").pop();
      const content = readFileSync(file, "utf-8");
      if (ext === "vue") {
        processVueFile(file, content, langObj, updateLang);
      } else {
        processJsFile(file, content, langObj, updateLang);
      }
    } catch (e) {
      logError(`处理文件失败: ${file}, 错误: ${e}`);
    }
  });
}

start();
